package com.zxtech.zzm.core.util

import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.telephony.TelephonyManager
import android.util.Log
import androidx.core.content.pm.PackageInfoCompat
import com.zxtech.zzm.core.BuildConfig
import com.zxtech.zzm.core.`interface`.CoreInterface
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Request.Builder
import okhttp3.Response
import org.json.JSONObject
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.UUID

open class DeviceUtil {
  companion object {
    var coreInterface: CoreInterface? = null
    var ID: String = ""
    fun getDeviceType(): String {
      return Build.MODEL
    }

    fun getAppVersionName(
      context: Context
    ): String {
      return context.packageManager.getPackageInfo(context.packageName, 0).versionName
    }

    fun getAppVersionCode(
      context: Context
    ): Long {
      return PackageInfoCompat.getLongVersionCode(
        context.packageManager.getPackageInfo(context.packageName, 0)
      )
    }

    fun getAppPackageName(context: Context): String {
      return context.packageName
    }

    fun getAndroidSDKVersionCode(): Int {
      return Build.VERSION.SDK_INT
    }

    fun getAndroidSDKVersionName(): String {
      return Build.VERSION.RELEASE
    }

    fun isDebug(): Boolean {
      return BuildConfig.DEBUG
    }

    fun translateAndroidVersion(): String {
      return when (getAndroidSDKVersionCode()) {
        7 -> "Android 2.1 Eclair"
        8 -> "Android 2.2 Froyo"
        9 -> "Android 2.3 Gingerbread"
        10 -> "Android 2.3.3 Gingerbread"
        11 -> "Android 3.0 Honeycomb"
        12 -> "Android 3.1 Honeycomb"
        13 -> "Android 3.2 Honeycomb"
        14 -> "Android 4.0 IceCreamSandwich"
        15 -> "Android 4.0.3 IceCreamSandwich"
        16 -> "Android 4.1 Jelly Bean"
        17 -> "Android 4.2 Jelly Bean"
        18 -> "Android 4.3 Jelly Bean"
        19 -> "Android 4.4 KitKat"
        20 -> "Android 4.4 KitKat Wear"
        21 -> "Android 5.0 Lollipop"
        22 -> "Android 5.1 Lollipop"
        23 -> "Android 6.0 Marshmallow"
        24 -> "Android 7.0 Nougat"
        25 -> "Android 7.1.1 Nougat"
        26 -> "Android 8.0 Oreo"
        27 -> "Android 8.1 Oreo"
        28 -> "Android 9.0 Pie"
        29 -> "Android 10.0 Q"
        30 -> "Android 11.0 R"
        31 -> "Android S Preview"
        else -> "unknown"
      }
    }

    fun getTerminalID(): String {
      return ID
    }

    fun initTerminalID() {
      Log.e("zzm debug", "initTerminalID")
      val mContext: Context = CommonUtil.getAppContext()
      ID = getTerminalIDFromSp(mContext)
      if (ID.isNullOrEmpty()) {
        ID = getTerminalIDFromZXTablet(mContext)
        if (ID.isNullOrEmpty()) {
          var serial = UUID.randomUUID().toString().replace("-", "")
          Log.e("zzm debug", "serial before: $serial")
          val cpuSerial = getCPUSerial()
          var phoneIMEI = ""
          try {
            phoneIMEI = getPhoneIMEI(mContext)
          } catch (e: Exception) {
            e.printStackTrace()
          }
          if (cpuSerial.isNotEmpty()) {
            serial = cpuSerial
          }
          if (phoneIMEI.isNotEmpty()) {
            serial = phoneIMEI
          }
          Log.e("zzm debug", "serial after: $serial")
          CoroutineScope(Dispatchers.Main).launch {
            withContext(Dispatchers.IO) {
              getTerminalIDFromServer(serial)
            }
          }
          if (ID.isNullOrEmpty()) {
            Log.e("zzm debug", "ID isNullOrEmpty : $ID")
            CoroutineScope(Dispatchers.IO).launch {
              delay(1000 * 5)
              initTerminalID()
            }
          } else {
            SharedprefsUtil.saveData(mContext, "TerminalID", ID)
            coreInterface?.onTerminalIDInited()
          }
        } else {
          SharedprefsUtil.saveData(mContext, "TerminalID", ID)
          coreInterface?.onTerminalIDInited()
        }
      } else {
        coreInterface?.onTerminalIDInited()
      }
    }

    private suspend fun getTerminalIDFromServer(serial: String) {
      withContext(Dispatchers.IO) {
        val client = OkHttpClient()
        val url = ("http://www.zx-link.com/f/mobile/applogin?httpCmd=getTerminalId&imsi="
            + serial)
        Log.e("zzm debug", "url = $url")
        val request: Request = Builder().url(url).build()
        try {
          val response: Response = client.newCall(request).execute()
          if (response.isSuccessful) {
            val resp = response.body?.string().toString()
            ID = JSONObject(resp).getString("content")
            SharedprefsUtil.saveData(CommonUtil.getAppContext(), "TerminalID", ID)
            coreInterface?.onTerminalIDInited()
          } else {
            throw IOException("Unexpected code $response")
          }
        } catch (e: Exception) {
          Log.e("zzm debug", "getTerminalIDFromServer Exception")
          e.printStackTrace()
        }
      }
    }

    private fun getTerminalIDFromSp(context: Context): String {
      return SharedprefsUtil.getSP(context).getString("TerminalID", "").toString()
    }

    private fun getTerminalIDFromZXTablet(context: Context): String {
      var id = ""
      var firstAppContext: Context?
      try {
        firstAppContext =
          context.createPackageContext("com.zxtech.zzm.zxtablet", Context.CONTEXT_IGNORE_SECURITY)
        val sharedPreferences = firstAppContext?.getSharedPreferences(
          "ZXTABLET_PREFERENCE",
          Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE
        )
        id = sharedPreferences?.getString("TerminalID", "").toString()
      } catch (e: NameNotFoundException) {
        e.printStackTrace()
      }
      return id
    }

    fun getCPUSerial(): String {
      var deviceInfo = ""
      try {
        val p = Runtime.getRuntime().exec("busybox cat /proc/cpuinfo")
        val `in` = BufferedReader(InputStreamReader(p.inputStream))
        var line: String? = null
        while (`in`.readLine().also { line = it } != null) {
          deviceInfo = line!!.trim { it <= ' ' }
        }
        deviceInfo = deviceInfo.split(":").toTypedArray()[1].trim { it <= ' ' }
      } catch (e: java.lang.Exception) {
        e.printStackTrace()
      }
      return deviceInfo
    }

    private fun getPhoneIMEI(context: Context): String {
      val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
      var imei: String? = null
      imei = if (VERSION.SDK_INT >= VERSION_CODES.O) {
        telephonyManager.imei
      } else {
        telephonyManager.deviceId
      }
      return imei
    }

    /**
     * 反射获取 deviceId
     *
     * @param context
     * @param slotId  slotId为卡槽Id，它的值为 0、1；
     * @return
     */
    private fun getDeviceIdByReflect(
      context: Context,
      slotId: Int
    ): String {
      try {
        val tm = context.applicationContext.getSystemService(Context.TELEPHONY_SERVICE)
        val method = tm.javaClass.getMethod("getDeviceId", Int.javaClass)
        return method.invoke(tm, slotId)
          .toString()
      } catch (e: Throwable) {

      }
      return ""
    }
  }
}